//@author A0083782W
#include "OutputDisplay.h"
#include<iostream>   
#include<sstream>   
#include <vector>   
using namespace std; 

//@author A0087294R
OutputDisplay::OutputDisplay(){
	EventStoragePtr newStoragePtr = &EventStorage::get();
	_eventList = newStoragePtr->getEventVectorPtr();
	upcomingText = NULL_STRING;
    inputText = NULL_STRING;
	shouldUpcomingClear = false;
	_shutDown = false;
	_hasDue = false;
}

void OutputDisplay::showHint (const string& hint) {
	hintText = hint;
}

string OutputDisplay::getHintText () {
	return hintText;
}

//@author A0105495A
string OutputDisplay::getStatus() {
	string result = NULL_STRING;
	result += STRING_STATUS1;
	result += NEW_LINE;
	result += STRING_STATUS2;
	result += NEW_LINE;
	result += getString (TableCharSet[(pos_int)TableChar::SINGLE_HORIZONTAL], ACTION_TOTAL_LENGTH);
	result += NEW_LINE;
	result += STRING_STATUS3;
	result += to_string (EventStorage::get().getEventVectorPtr()->size());
	result += NEW_LINE;
	result += STRING_STATUS4;
	result += to_string (ActionList::get().sizeOfActions());
	result += NEW_LINE;
	result += getString (TableCharSet[(pos_int)TableChar::SINGLE_HORIZONTAL], ACTION_TOTAL_LENGTH);
	result += NEW_LINE;
	CurrentTime nowClock;
	Time newClock;
	newClock.setSecondDisplay (true);
	newClock = nowClock;
	result += newClock.toTimeString();
	result += SPACE_STRING;
	result += newClock.toDateString();
	result += SPACE_STRING;
	result += newClock.toDayOfWeekString();
	return result;
}

void OutputDisplay::shutDown () {
	_shutDown = true;
}

void OutputDisplay::clearConsole() {
	shouldUpcomingClear = true;
}

bool OutputDisplay::shouldShutDown() const {
	return _shutDown;
}
	
//@author A0105495A
void OutputDisplay::showConfig (){      
    upcomingText += STRING_SHOW_CONFIG_A;
    upcomingText += NEW_LINE;
    upcomingText += STRING_SHOW_CONFIG_B;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayDateConfig(){
    upcomingText += STRING_DATE_CONFIG_A;
    upcomingText += NEW_LINE;
    upcomingText += STRING_DATE_CONFIG_B;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayTimeConfig(){
    upcomingText += STRING_TIME_CONFIG_A;
    upcomingText += NEW_LINE;
    upcomingText += STRING_TIME_CONFIG_B;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayOrderConfig(){
    upcomingText += STRING_ORDER_CONFIG_A;
    upcomingText += NEW_LINE;
    upcomingText += STRING_ORDER_CONFIG_B;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayExitConfig(){
    upcomingText += STRING_EXIT_CONFIG;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayDateConfiged(){
    upcomingText += STRING_DATE_CONFIGED;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayIllegalConfig(){
    upcomingText += STRING_ILLEGAL_CONFIG;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayTimeConfiged(){
    upcomingText += STRING_TIME_CONFIGED;
    upcomingText += NEW_LINE;
}

void OutputDisplay::displayOrderConfiged(){
    upcomingText += STRING_ORDER_CONFIGED;
    upcomingText += NEW_LINE;
}

OutputDisplay& OutputDisplay::get() {
	static OutputDisplay newInstance;
	return newInstance;
}

string OutputDisplay::getAcionListText() {
	string result;
	pos_int length = ActionList::get().sizeOfActions();
	for (pos_int i = 0; i < length; i++) {
		result += toActionString (ActionList::get()[i]);
	}
	return result;
}

bool OutputDisplay::getShouldClearUpComing() {
	bool temp = shouldUpcomingClear;
	if (shouldUpcomingClear == true) {
		shouldUpcomingClear = false;
	}
	return temp;
}

void OutputDisplay::displayError(IllegalInput errorType){
    upcomingText += STRING_ERROR;
    switch(errorType){
    case IllegalInput::ADD_TOO_MANY_PARAMETERS:
		upcomingText += STRING_ERROR_ADD_TOO_MANY_PARAMETERS;
        upcomingText += NEW_LINE;
        break;
	case IllegalInput::ADD_NO_TASK_DESCIPTION:
        upcomingText += STRING_ERROR_ADD_NO_TASK_DESCIPTION;
        upcomingText += NEW_LINE;         
        break;
    case IllegalInput::DELETE_ILLEGAL_PARAMETER:
        upcomingText += STRING_ERROR_DELETE_ILLEGAL_PARAMETER;
        upcomingText += NEW_LINE;         
        break;
	case IllegalInput::MODIFY_NO_INDEX:
        upcomingText += STRING_ERROR_MODIFY_ILLEGAL_PARAMETER;
        upcomingText += NEW_LINE;         
        break;
    case IllegalInput::SEARCH_ILLEGAL_FLAGS:
        upcomingText += STRING_ERROR_SEARCH_ILLEGAL_FLAGS;
        upcomingText += NEW_LINE;         
        break;
    case IllegalInput::UNDO_ILLEAGAL_NUMBER:
        upcomingText += STRING_ERROR_UNDO_ILLEAGAL_NUMBER;
        upcomingText += NEW_LINE;         
        break; 
	case IllegalInput::UNKNOW_CHARACTERS:
		upcomingText += STRING_ERROR_UNKNOW_CHARACTERS;
		upcomingText += NEW_LINE;
		break;
	//The user never inputSTRING_EMPTY_NO_MARK any filter for mark action
	case IllegalInput::MARK_NO_FILTER:
		upcomingText += STRING_ERROR_MARK_NO_FILETER;
		upcomingText += NEW_LINE;
		break;
	case IllegalInput::MARK_NO_INDEX:
		upcomingText += STRING_ERROR_MARK_NO_INDEX;
		upcomingText += NEW_LINE;
		break;
    default:
         upcomingText += STRING_ERROR_UNKNOWN;
         upcomingText += NEW_LINE;         
         break;                                                     
    }
}

void OutputDisplay::displayEvents (vector<pos_int> _IDList){ 
	shouldUpcomingClear = true;
	pos_int nIndex = 1;
	pos_int marginSize = 0;
	const pos_int maxSize = (*EventStorage::get().getEventVectorPtr()).size();
	if (maxSize != 0) {
		marginSize = to_string (maxSize).size() + 1;
	}
	else {
		upcomingText += NEW_LINE;
		return;
	}
	
	for (auto i:_IDList) {
        upcomingText += toStringOfEvent((*_eventList)[i], nIndex, marginSize);
		nIndex++;
	 }
}

string OutputDisplay::getTodayText() {
	return todayText;
}

void OutputDisplay::showUpcomingString (const string & content) {
	upcomingText += NEW_LINE;
	upcomingText += content;
}

string OutputDisplay::getMissedText() {
	return missedText;
}
string OutputDisplay::getFavouriteText() {
	return favouriteText;
}
string OutputDisplay::getFloatingText() {
	return floatingText;
}

//@author A0083782W
void OutputDisplay::displayToday (vector<pos_int> _IDList) {
	pos_int nIndex = 1;
	pos_int marginSize = 0;
	todayText = NULL_STRING;
	const pos_int maxSize = (*EventStorage::get().getEventVectorPtr()).size();
	if (maxSize != 0) {
		marginSize = to_string (maxSize).size() + 1;
	}
	else {
		todayText += NEW_LINE;
		return;
	}
	
	for (auto i:_IDList) {
		todayText += toStringOfEvent((*_eventList)[i], nIndex, marginSize);
		nIndex++;
	}
}
void OutputDisplay::displayMissed (vector<pos_int> _IDList) {
	pos_int nIndex = 1;
	pos_int marginSize = 0;
	missedText = NULL_STRING;
	const pos_int maxSize = (*EventStorage::get().getEventVectorPtr()).size();
	if (maxSize != 0) {
		marginSize = to_string (maxSize).size() + 1;
	}
	else {
		missedText += NEW_LINE;
		return;
	}
	
	for (auto i:_IDList) {
		missedText += toStringOfEvent((*_eventList)[i], nIndex, marginSize);
		nIndex++;
	}
}
void OutputDisplay::displayFavourite (vector<pos_int> _IDList) {
	pos_int nIndex = 1;
	pos_int marginSize = 0;
	favouriteText = NULL_STRING;
	const pos_int maxSize = (*EventStorage::get().getEventVectorPtr()).size();
	if (maxSize != 0) {
		marginSize = to_string (maxSize).size() + 1;
	}
	else {
		favouriteText += NEW_LINE;
		return;
	}
	
	for (auto i:_IDList) {
		favouriteText += toStringOfEvent((*_eventList)[i], nIndex, marginSize);
		nIndex++;
	}
}
void OutputDisplay::displayFloating (vector<pos_int> _IDList) {
	pos_int nIndex = 1;
	pos_int marginSize = 0;
	floatingText = NULL_STRING;
	const pos_int maxSize = (*EventStorage::get().getEventVectorPtr()).size();
	if (maxSize != 0) {
		marginSize = to_string (maxSize).size() + 1;
	}
	else {
		floatingText += NEW_LINE;
		return;
	}
	
	for (auto i:_IDList) {
		floatingText += toStringOfEvent((*_eventList)[i], nIndex, marginSize);
		nIndex++;
	}
}
void OutputDisplay::showAdded(string detailAdded){
    upcomingText += STRING_QUOTATION;
    upcomingText += detailAdded;
    upcomingText += STRING_QUOTATION;
    upcomingText += SPACE_STRING;
    upcomingText += STRING_ADDED;
    upcomingText += NEW_LINE;
}
void OutputDisplay::showUndoneSuccess(pos_int stepNum){
    upcomingText += to_string(stepNum);
	upcomingText += SPACE_STRING;
    upcomingText += STRING_UNDONE;
    upcomingText += NEW_LINE;
}

void OutputDisplay::showMarked(vector<pos_int> _IDMarked,vector<pos_int> _IDIllegal){
	if((_IDMarked.size()==0)&&(_IDIllegal.size()==0)){
        upcomingText += STRING_EMPTY_NO_MARK;
		upcomingText += NEW_LINE;
    } else {
        if(_IDMarked.size()!=0){
            upcomingText += STRING_MARKED;
            for (auto i:_IDMarked) {
		        upcomingText += to_string(i);
		        upcomingText += SPACE_COMMA_SPACE;
	        }
            upcomingText += NEW_LINE;
        }
        if(_IDIllegal.size()!=0){
            upcomingText += STRING_NOT_MARKED;
            for (auto i:_IDIllegal) {
		        upcomingText += to_string(i);
		        upcomingText += SPACE_COMMA_SPACE;
            }
        }	 
    }
}

void OutputDisplay::showSave() {
	upcomingText += STRING_SAVE_SUCCESS;
	upcomingText += NEW_LINE;
}

void OutputDisplay::showdeleted(vector<pos_int> _IDDeleted,vector<pos_int> _IDIllegal){
	if((_IDDeleted.size()==0)&&(_IDIllegal.size()==0)){
        upcomingText += STRING_EMPTY_NO_DELETE;
    } 
	else {
        if(_IDDeleted.size()!=0){
            upcomingText += STRING_DELETED;
            for (auto i:_IDDeleted) {
		        upcomingText += to_string(i);
		        upcomingText += SPACE_COMMA_SPACE;
	        }
            upcomingText += NEW_LINE;
        }
        if(_IDIllegal.size()!=0){
            upcomingText += STRING_NOT_DELETED;
            for (auto i:_IDIllegal) {
		        upcomingText += to_string(i);
		        upcomingText += SPACE_COMMA_SPACE;
            }
			upcomingText += NEW_LINE;
        }	 
    }
}

void OutputDisplay::showModifyStep2 (const vector<pos_int>& IDs) {
	upcomingText += STRING_YOU_HAVE_SELECTED;
	for (auto i:IDs) {
		upcomingText += to_string (i);
		upcomingText += SPACE_COMMA_SPACE;
	}
	upcomingText += STRING_FOR_EDITING;
	upcomingText += NEW_LINE;
	upcomingText += STRING_MODIFY_PROMPT;
	upcomingText += NEW_LINE;
	upcomingText += STRING_MODIFY_OPTION;
	upcomingText += NEW_LINE;
}
void OutputDisplay::showModifyStep3 (ModifyType newType) {
	switch (newType) {
	case ModifyType::END:     
		upcomingText += STRING_MODIFY_END;
		break;
	case ModifyType::DETAIL:
        upcomingText += STRING_PLEASE_ENTER;
		upcomingText += STRING_DETAIL;
		upcomingText += STRING_COLON_SPACE;
		break;
	case ModifyType::TIME:
        upcomingText += STRING_PLEASE_ENTER;
		upcomingText += STRING_TIME;
		upcomingText += STRING_COLON_SPACE;
		break;
	case ModifyType::REPEATRULE:
        upcomingText += STRING_PLEASE_ENTER;
		upcomingText += STRING_REPEAT;
		upcomingText += STRING_COLON_SPACE;
		break;
	case ModifyType::REMIND_TIME:
        upcomingText += STRING_PLEASE_ENTER;
		upcomingText += STRING_REMIND_TIME;
		upcomingText += STRING_COLON_SPACE;
		break;
	case ModifyType::TAGS:
        upcomingText += STRING_PLEASE_ENTER;
		upcomingText += STRING_TAGS_SMALL;
		upcomingText += STRING_COLON_SPACE;
		break;
	}
	upcomingText += NEW_LINE;
}

void OutputDisplay::showModifyStep1Error(){
	upcomingText += STRING_MODIFY_EMPTY;
	upcomingText += NEW_LINE;	 
}

void OutputDisplay::showModifyStep2Error(){
	upcomingText += STRING_MODIFY_STEP2_ERROR;
	upcomingText += NEW_LINE;	
}

void OutputDisplay::showModifySuccess (const vector<pos_int>& modifiedIDs, const vector<pos_int>& notModifiedIDs) {
	if (modifiedIDs.size() != 0) {
		for (auto i:modifiedIDs) {
			upcomingText += to_string (i);
			upcomingText += SPACE_COMMA_SPACE;
		}
	}
	else {
		upcomingText += STRING_NOTHING;
	}
	upcomingText += STRING_MODIFY_SUCCESS;
	upcomingText += NEW_LINE;

	if (notModifiedIDs.size() != 0) {
		for (auto i:notModifiedIDs) {
			upcomingText += to_string (i);
			upcomingText += SPACE_COMMA_SPACE;
		}
		upcomingText += STRING_MODIFY_FAIL;
		upcomingText += NEW_LINE;
	}
}

string OutputDisplay::getUpcomingText(){
	string temp = upcomingText;
	upcomingText = NULL_STRING;
	return temp;
}

void OutputDisplay::displayHistory(con_str& history) {
	inputText = history;
}

string OutputDisplay::getInputText(){
    string temp = inputText;
	inputText = NULL_STRING;
	return temp;
}

string OutputDisplay::getDueText () {
	return dueMsg;
}

bool OutputDisplay::availableDue() const {
	return _hasDue;
}

void OutputDisplay::setAvailableDue (bool newBool) {
	_hasDue = newBool;
}
void OutputDisplay::showDue (Event& anEvent) {
	dueMsg = NULL_STRING;
	EventVector *ptr =EventStorage::get().getEventVectorPtr();
	
	dueMsg += anEvent.getDetails();
	dueMsg += NEW_LINE;
	dueMsg += toDurationString (anEvent.getStartTime(), anEvent.getEndTime(), anEvent.isDuration(), true);
	dueMsg += NEW_LINE;
	if (anEvent.isDuration()) {
		dueMsg += toDurationString (anEvent.getStartTime(), anEvent.getEndTime(), anEvent.isDuration(), false);
		dueMsg += NEW_LINE;
	}
	dueMsg += toRemindString (anEvent.getRemindTime());
	dueMsg += NEW_LINE;
	dueMsg += toStringOfRepeatRule (anEvent.getRepeatRule());
	dueMsg += NEW_LINE;
	vector<string> const * const tagPtr = anEvent.getTagPtr();
	if (tagPtr->size() != 0) {
		dueMsg += STRING_TAGS;
		for (auto i:*tagPtr) {
			dueMsg += i;
			dueMsg += SPACE_STRING;
		}
		dueMsg += NEW_LINE;
	}
	dueMsg += NEW_LINE;
	dueMsg += STRING_DUE_YES;
	dueMsg += NEW_LINE;
	dueMsg += STRING_DUE_NO;
}
